<?php
/**
 * CONTENIDO extension pack (mpContenidoX), consists of multiple classes to
 * provide more features for Plugins/Modules.
 *
 * @package     mpContenidoX
 * @subpackage  Form
 * @author      Murat Purc <murat@purc.de>
 * @copyright   Copyright (c) 2008-2012 Murat Purc (http://www.purc.de)
 * @license     http://www.gnu.org/licenses/gpl-2.0.html - GNU General Public License, version 2
 * @version     $Id: Base.class.php 21 2012-07-16 21:33:14Z purcaholic $
 */


defined('CON_FRAMEWORK') or die('Illegal call');


/**
 * Form class
 *
 * @package     mpContenidoX
 * @subpackage  Form
 * @author      Murat Purc <murat@purc.de>
 */
class mpForm_Base {

    const DISPLAY_ERRORS_DISABLED       = 1;
    const DISPLAY_ERRORS_RIGHT_TO_FIELD = 2;
    const DISPLAY_ERRORS_LEFT_TO_FIELD  = 3;
    const DISPLAY_ERRORS_AS_LIST        = 4;

    const FORM_RENDER_MODE_FORM   = 'form';
    const FORM_RENDER_MODE_VALUE  = 'value';

    protected $_form;

    protected $_template;

    protected $_isFormValid;

    protected $_stopValidationOnFirstError = false;

    protected $_isFormSend = false;


    public function __construct()
    {
        $this->_request = array();
        $this->_generateHash = false;
        $this->_isXHTML = true;
        $this->_form = array(); // @todo: should be removed...
        $this->_formTemplate = '';
        $this->_formObj = null;
        $this->_elements = array();
        $this->_errorClass = '';
        $this->_requiredErrorMsg = '%s';
        $this->_mainErrorMessage = '';
        $this->_errorMessageTemplate = '%s';
        $this->_errorMessageTemplateWrap = '%s';
    }


    public function setRequest($request)
    {
        $this->_request    = $request;
        $this->_isFormSend = (count($this->_request) > 0);
        $this->_takeoverRequestData();
    }


    public function getRequest()
    {
        return $this->_request;
    }


    public function getRequestItem($key, $default = null)
    {
        return isset($this->_request[$key]) ? $this->_request[$key] : null;
    }


    public function isXHTML($xhtml)
    {
        $this->_isXHTML = (bool) $xhtml;
    }


    public function setGenerateHash($generate)
    {
        $this->_generateHash = (bool) $generate;
    }


    public function setForm(array $form)
    {
        // form tag
        $this->_formObj = new mpForm_Element();
        foreach ($form as $attr => $value) {
            $this->_formObj->setAttribute($attr, $value);
        }
    }


    public function setFormTemplate($formTemplate)
    {
        $this->_formTemplate = $formTemplate;
    }


    public function setFormElements($elements)
    {
        foreach ($elements as $id => $item) {
            $this->setFormElement($id, $item);
        }
    }


    public function getFormElements()
    {
        return $this->_elements;
    }


    public function getFormElementsForDataView()
    {
        $elements = array();
        $collectedRadios = array();
        foreach ($this->getFormElements() as $id => $element) {
            $name = $element->getAttribute('name');
            if ('radio' == $element->getProperty('type')) {
                if (!in_array($name, $collectedRadios)) {
                    $radioElem = $this->_getOptionElementByName($name);
                    if ($radioElem) {
                        $collectedRadios[] = $name;
                        $elements[$id] = $radioElem;
                    }
                }
            } else {
                $elements[$id] = $element;
            }
        }
        return $elements;
    }


    public function setFormElement($id, $element)
    {
        // check/set id
        if (!isset($element['id'])) {
            $element['id'] = $id;
        }

        // set type
        $element['#type'] = $element['type'];

        // check/set validations
        if (isset($element['#validations']) && !is_array($element['#validations'])) {
            $element['#validations'] = array($element['#validations']);
        }

        // check/set accepted value
        if (isset($element['#acceptedValues']) && !is_array($element['#acceptedValues'])) {
            $element['#acceptedValues'] = array($element['#acceptedValues']);
        }

        // check/set required
        if (!isset($element['#required'])) {
            $element['#required'] = false;
        } else {
            $element['#required'] = (bool) $element['#required'];
        }

        // textarea
        if ('textarea' == $element['#type']) {
            unset($element['type']);
            if (!isset($element['cols'])) {
                $element['cols'] = '20';
            }
            if (!isset($element['rows'])) {
                $element['rows'] = '5';
            }
            if (!isset($element['rows'])) {
                $element['rows'] = '5';
            }
            if (isset($element['value'])) {
                $element['#value'] = $element['value'];
                unset($element['value']);
            } elseif (!isset($element['#value'])) {
                $element['#value'] = '';
            }
        }

        // select
        if ('select' == $element['#type']) {
            unset($element['type']);
        }

        // checkbox / radio
        if ('checkbox' == $element['#type'] || 'radio' == $element['#type']) {
            if (isset($element['checked'])) {
                $element['checked'] = 'checked';
            }
        }

        $elemObj = new mpForm_Element($element);

        if ($this->getRequestItem($elemObj->getAttribute('name'))) {
            $elemObj->setValue($this->getRequestItem($elemObj->getAttribute('name')));
        }

        $this->_elements[$id] = $elemObj;
    }


    public function getFormElement($id)
    {
        return isset($this->_elements[$id]) ? $this->_elements[$id] : null;
    }


    public function setErrorClass($class)
    {
        $this->_errorClass = (string) $class;
    }


    public function setAnswer($answer)
    {
        $this->_answer = $answer;
    }


    public function setSemiOptionalFields($fields)
    {
        if (is_array($fields)) {
            $this->_form['setSemiOptionalFields'] = $fields;
        }
    }


    public function setStopValidationOnFirstError($stop)
    {
        $this->_stopValidationOnFirstError = (bool) $stop;
    }


    /**
     * Set display error handling
     *
     * @param   int  $type  One of DISPLAY_ERROR_* constants
     * @return  void
     */
    public function setDisplayErrorHandling($type)
    {
        $this->_displayErrorHandlingType = (int) $type;
    }


    public function setRequiredErrorMsg($message = '%s')
    {
        $this->_requiredErrorMsg = $message;
    }


    public function setMainErrorMessage($message = '')
    {
        $this->_mainErrorMessage = (string) $message;
    }


    public function setErrorMessageTemplate($template = '%s', $templateWrap = '%s')
    {
        $this->_errorMessageTemplate = (string) $template;
        $this->_errorMessageTemplateWrap = (string) $templateWrap;
    }


    public function isFormValid()
    {
        if (isset($this->_isFormValid)) {
            return $this->_isFormValid;
        }

        $this->_isFormValid = true;

        $form   = $this->_formTemplate;
        foreach ($this->_elements as $element) {
            if (!$this->_isElementValid($element)) {
                $this->_isFormValid = false;
                if (true === $this->_stopValidationOnFirstError) {
                    break;
                }
            }
        }
        return $this->_isFormValid;
    }


    public function actionNew()
    {
#echo $this->_dumpVar($this->getRequest(), 'actionNew() request');
        return $this->_printForm(self::FORM_RENDER_MODE_FORM);
    }


    public function actionEdit()
    {
#echo $this->_dumpVar($this->getRequest(), 'actionEdit() request');
        return $this->_printForm(self::FORM_RENDER_MODE_FORM);
    }


    public function actionPreview()
    {
#echo $this->_dumpVar($this->getRequest(), 'actionPreview() request');
        return $this->_printForm(self::FORM_RENDER_MODE_VALUE);
    }


    public function actionSend()
    {
        return $this->_printSuccess();
    }


    public function storeFormData($formId)
    {
        global $sess, $sessFormData;
        $sess->register('sessFormData');
        $sessFormData[$formId] = array();
        foreach ($this->getRequest() as $name => $value) {
            $sessFormData[$formId][$name] = urlencode($value);
        }
    }


    public function fetchStoredFormData($formId)
    {
        global $sessFormData;
        if (!isset($sessFormData) || !is_array($sessFormData) || !is_array($sessFormData[$formId])) {
            return null;
        }
        $data = array();
        foreach ($sessFormData[$formId] as $name => $value) {
            $data[$name] = urldecode($value);
        }
        return $data;
    }


    public function deleteStoredFormData($formId)
    {
        global $sess, $sessFormData;
        if (isset($sessFormData) && is_array($sessFormData) && is_array($sessFormData[$formId])) {
            $sess->register('sessFormData');
            unset($sessFormData[$formId]);
        }
    }


    public function getTemplate()
    {
        if (!isset($this->_template)) {
            $this->_template = new Template();
        }
        return $this->_template;
    }


    protected function _printForm($renderMode = mpForm_Base::FORM_RENDER_MODE_FORM)
    {
        $template = $this->getTemplate();

        $this->_addFormHashElement($renderMode);

        // set form starting tag
        $template->set('s', 'FORM_START', $this->_renderFormTag($this->_formObj));

        // set hidden fields
        $hiddenFields = $this->_renderAllHiddenFields($renderMode);
        $template->set('s', 'FORM_HIDDEN_ELEMENTS', $hiddenFields);

        // set main error message
        $errorMessage = ($this->isFormValid()) ? '' : $this->_mainErrorMessage;
        $template->set('s', 'FORM_MAIN_ERROR_MESSAGE', $errorMessage);

        // set error message list
        $errorList = $this->_renderErrorList($renderMode);
        $template->set('s', 'FORM_ERRORLIST', $errorList);

        // set elements
        if ($renderMode == self::FORM_RENDER_MODE_FORM) {
            $elements = $this->_elements;

            foreach ($elements as $id => $element) {
                if ('hidden' == $element->getProperty('type')) {
                    continue;
                }

                $name  = $element->getAttribute('name');
                $elem  = $this->_createFormElement($element, $renderMode);
                $label = $this->_createFormElementLabel($element, $renderMode);

                $template->set('s', 'FORM_ELEMENT.' . strtoupper($id), $elem);
                $template->set('s', 'FORM_LABEL.' . strtoupper($id), $label);
            }

        } else {
            $elements = $this->getFormElementsForDataView();

            foreach ($elements as $id => $element) {
                if ('hidden' == $element->getProperty('type')) {
                    continue;
                }

                $name  = $element->getAttribute('name');
                $elem  = $this->_createFormElement($element, $renderMode);
                $label = $this->_createFormElementLabel($element, $renderMode);

                if ('radio' == $element->getProperty('type')) {
                    $template->set('s', 'FORM_ELEMENT.' . strtoupper($name), $elem);
                    $template->set('s', 'FORM_LABEL.' . strtoupper($name), $label);
                } else {
                    $template->set('s', 'FORM_ELEMENT.' . strtoupper($id), $elem);
                    $template->set('s', 'FORM_LABEL.' . strtoupper($id), $label);
                }
            }

        }

        // set form ending tag
        $template->set('s', 'FORM_END', '</form>');

        // generate template
        return $template->generate($this->_formTemplate, 1);
    }


    protected function _createFormElement(mpForm_Element $element, $renderMode)
    {
        $name = $element->getAttribute('name');

        if ($this->_isFormSend && $renderMode == self::FORM_RENDER_MODE_FORM && !$this->_isElementValid($element)) {
            if (in_array($name, $this->_form['setSemiOptionalFields'])) {
                // classname for elements having errors
                $element->addToClassAttribute($this->_getSetting($element, 'errorClass'));
            } else {
                // classname for elements having errors
                $element->addToClassAttribute($this->_getSetting($element, 'errorClass'));
            }
        }

        switch ($element->getProperty('type')) {
            case 'text':
            case 'password':
            case 'submit':
            case 'reset':
            case 'image':
            case 'hidden':
            case 'file':
            case 'checkbox':
            case 'radio':
                $field = $this->_renderInputField($element, $renderMode);
                break;
            case 'textarea':
                $field = $this->_renderTextareaField($element, $renderMode);
                break;
            case 'select':
                $field = $this->_renderSelectField($element, $renderMode);
                break;
        }

        // handle error messages
        if ($element->getProperty('isValid') === false && $element->getProperty('errorMsg')) {
            if (self::DISPLAY_ERRORS_RIGHT_TO_FIELD == $this->_displayErrorHandlingType) {
                // add error message right to field
                $msg = $this->_renderMessage($element, $element->getProperty('errorMsg'));
                $field .= sprintf($this->_errorMessageTemplate, $msg);
            } elseif (self::DISPLAY_ERRORS_LEFT_TO_FIELD == $this->_displayErrorHandlingType) {
                // add error message left to field
                $msg = $this->_renderMessage($element, $element->getProperty('errorMsg'));
                $field = sprintf($this->_errorMessageTemplate, $msg) . $field;
            }
        }

        return $field;
    }


    protected function _createFormElementLabel(mpForm_Element $element, $renderMode)
    {
        if ($renderMode == self::FORM_RENDER_MODE_VALUE && $element->getProperty('previewLabel')) {
            return $element->getProperty('previewLabel');
        } elseif ($element->getProperty('label')) {
            $label = new mpForm_Element();
            $label->setAttribute('for', $element->getAttribute('id'));
            if ($element->getProperty('labelClass')) {
                $label->setAttribute('class', $element->getAttribute('labelClass'));
            }
            if ($element->getProperty('labelCss')) {
                $label->setAttribute('style', $element->getAttribute('labelCss'));
            }
            $label->setValue($element->getProperty('label'));
            return $this->_renderLabel($label, $renderMode);
        } else {
            return '';
        }
    }


    protected function _printSuccess()
    {
        if (false !== strpos($this->_answer, '###sent_data###')) {
            $this->_answer = str_replace('###sent_data###', '', $this->_answer);
        }
        return $this->_answer;
    }


    protected function _isElementValid(mpForm_Element $element)
    {
        if (null !== $element->getProperty('isValid')) {
            // element was validated before, return it's validation result
            return $element->getProperty('isValid');
        } elseif (false == $this->_isFormSend) {
            return true;
        }

        $name = $element->getAttribute('name');

        if ('file' !== $element->getProperty('type')) {

            // ############ Process form fields

            $currentValue = isset($this->_request[$name]) ? $this->_request[$name] : '';

            // is required check
            if (true === $element->getProperty('required') && empty($currentValue)) {
                $element->setProperty('isValid', false);
                $msg = $this->_getSetting($element, 'requiredErrorMsg');
                $element->setProperty('errorMsg', $this->_renderMessage($element, $msg));
                return false;
            }

            // field is not required and not set, get out here...
            if (empty($currentValue)) {
                return true;
            }

        } else {

            // ############ Process file upload

            $currentValue = isset($_FILES[$name]) ? $_FILES[$name] : array(
                'name'     => '',
                'type'     => '',
                'tmp_name' => '',
                'error'    => UPLOAD_ERR_OK,
                'size'     => 0
            );

            // is required check
            if (true === $element->getProperty('required') && empty($currentValue['name'])) {
                $element->setProperty('isValid', false);
                $msg = $this->_getSetting($element, 'requiredErrorMsg');
                $element->setProperty('errorMsg', $this->_renderMessage($element, $msg));
                return false;
            }

            // upload file is not required and not set, get out here...
            if (empty($currentValue['name'])) {
                return true;
            }
        }

        // process all defined validations...
        if ($element->getProperty('validations')) {
            foreach ($element->getProperty('validations') as $validation) {
                if (is_callable($validation['callback'])) {
                    $params = array_reverse($validation['params']);
                    $params[] = $currentValue;
                    $params = array_reverse($params);
                    $success = call_user_func_array($validation['callback'], $params);
                    if (!$success) {
                        $errorMsg = $validation['errorMsg'];
                        foreach ($validation['params'] as $pos => $param) {
                            $errorMsg = str_replace('{' . $pos . '}', $param, $errorMsg);
                        }
                        $errorMsg = $this->_renderMessage($element, $errorMsg);
                        $element->setProperty('isValid', false);
                        $element->setProperty('errorMsg', $errorMsg);
                        return false;
                    }
                }
            }
        }

        $element->setProperty('isValid', true);

        return true;
    }


    protected function _getSetting(mpForm_Element $element, $name)
    {
        if (null !== $element->getProperty($name)) {
            return $element->getProperty($name);
        } else {
            $name = '_' . $name;
            if ($this->$name) {
                return $this->$name;
            }
        }
        throw new Exception('Not supported setting ' . $name . '!');
    }


    protected function _renderMessage(mpForm_Element $element, $message)
    {
        foreach ($element->getAttributes() as $name => $value) {
            $message = str_replace('{' . $name . '}', $value, $message);
        }
        foreach ($element->getProperties() as $name => $value) {
            $message = str_replace('{#' . $name . '}', $value, $message);
        }
        return $message;
    }


    protected function _renderFormTag(mpForm_Element $element, $renderMode = mpForm_Base::FORM_RENDER_MODE_FORM)
    {
        if ($renderMode !== self::FORM_RENDER_MODE_VALUE) {
            $field = '<form';
            foreach ($element->getAttributes() as $k => $v) {
                $field .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
            }
            $field .=  '>';
        } else {
            $field = '';
        }
        return $field;
    }


    protected function _renderAllHiddenFields($renderMode)
    {
        // render all hidden fields
        $hiddenFields = '';
        foreach ($this->_elements as $id => $element) {
            if ('hidden' == $element->getProperty('type')) {
                $hiddenFields .= $this->_createFormElement($element, $renderMode);
            }
        }
        return $hiddenFields;
    }


    protected function _renderInputField(mpForm_Element $element, $renderMode = mpForm_Base::FORM_RENDER_MODE_FORM)
    {
        $type  = $element->getProperty('type');
        $name  = $element->getAttribute('name');
        if ($renderMode !== self::FORM_RENDER_MODE_VALUE || $element->getProperty('forceRender') == true) {
            $field = '<input';
            foreach ($element->getAttributes() as $k => $v) {
                if ($k == 'checked' && $type == 'checkbox' && $this->_isXHTML) {
                    $field .= ' ' . $k . '"';
                } elseif ($k == 'selected' && $type == 'checkbox' && $this->_isXHTML) {
                    $field .= ' ' . $k . '"';
                } elseif ($type == 'password' && $k == 'value') {
                    // never ever abandon the password
                    $field .= ' ' . $k . '=""';
                } elseif ($type == 'file' && $k == 'value') {
                    // there is no value to render for files
                } else {
                    $field .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
                }
            }
            $field .= ($this->_isXHTML) ? ' />' : '>';
        } else {
            if ($type == 'password' && $k == 'value') {
                // never ever abandon the password
                $field = str_repeat('*', strlen($element->getValue()));
            } elseif ($type == 'file' && isset($_FILES[$name])) {
                // uploaded filename
                $field = $_FILES[$name]['name'];
            } elseif ($type == 'hidden') {
                // hidden field
                $field = '';
            } else {
                $field = $element->getValue();
            }
        }
        return $field;
    }


    protected function _renderTextareaField(mpForm_Element $element, $renderMode = mpForm_Base::FORM_RENDER_MODE_FORM)
    {
        if ($renderMode !== self::FORM_RENDER_MODE_VALUE) {
            $field = '<textarea';
            foreach ($element->getAttributes() as $k => $v) {
                $field .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
            }
            $field .= '>' . htmlspecialchars($element->getValue()) . '</textarea>';
        } else {
            $field = $element->getValue();
        }
        return $field;
    }


    protected function _renderSelectField(mpForm_Element $element, $renderMode = mpForm_Base::FORM_RENDER_MODE_FORM)
    {
        if ($renderMode !== self::FORM_RENDER_MODE_VALUE) {
            $field = '<select';
            foreach ($element->getAttributes() as $k => $v) {
                $field .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
            }
            $field .= '>';

            foreach ($element->getProperty('options') as $option) {
                if (isset($option['s']) && $option['s'] == true) {
                    $selected = ($this->_isXHTML) ? ' selected="selected"' : ' selected';
                } else {
                    $selected = '';
                }
                $field .= '<option value="' . htmlspecialchars($option['v']) . '"' . $selected . '>' . $option['t'] . '</option>';
            }
            $field .=  '</select>';
        } else {
            $field = '';
            foreach ($element->getProperty('options') as $option) {
                if (isset($option['s']) && $option['s'] == true) {
                    $field = $option['t'];
                    break;
                }
            }
        }
        return $field;
    }


    protected function _renderLabel(mpForm_Element $element, $renderMode = mpForm_Base::FORM_RENDER_MODE_FORM)
    {
        if ($renderMode == self::FORM_RENDER_MODE_FORM) {
            $field = '<label';
            foreach ($element->getAttributes() as $k => $v) {
                $field .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
            }
            $field .=  '>' . $element->getValue() . '</label>';
            if ($element->getProperty('requiredTag')) {
                $field .= $element->getProperty('requiredTag');
            }
        } else {
            $field = $element->getValue();
        }
        return $field;
    }


    protected function _renderErrorList($renderMode)
    {
        $errorList = '';
        if ($renderMode == self::FORM_RENDER_MODE_FORM && !$this->isFormValid()) {
            // @todo: won't work, fix it...
            if ($this->_displayErrorHandlingType == self::DISPLAY_ERRORS_AS_LIST) {
                // error list
                foreach ($this->getFormElements() as $id => $element) {
#echo "<pre>id: " . $id . "\n" . "isValid: " . $element->getProperty('isValid')  . "\n" . "errorMsg: " . $element->getProperty('errorMsg')  . "\n" . "</pre>";
                    if ($element->getProperty('isValid') === false && $element->getProperty('errorMsg')) {
                        $errorList .= sprintf($this->_errorMessageTemplate, $element->getProperty('errorMsg'));
                    }
                }
                if ($errorList !== '') {
                    return sprintf($this->_errorMessageTemplateWrap, $errorList);
                }
            } elseif ($this->_displayErrorHandlingType == self::DISPLAY_ERRORS_DISABLED) {
                // general error message
                $errorList = $this->_errorMessageTemplate;
            }
        }

        return $errorList;
    }


    protected function _addFormHashElement($renderMode)
    {
        // but first of all, create the hash element...
        if ($this->_generateHash) {
            global $sess, $sessFormHash;
            if ($renderMode == self::FORM_RENDER_MODE_FORM) {
                $sess->register('sessFormHash');
                $sessFormHash = sha1(str_shuffle((string) time() . (string) rand(1, 9999999999)));
                $hashElement  = array(
                    'type' => 'hidden', 'name' => 'formHash', 'value' => $sessFormHash
                );
            } else {
                $hashElement = array(
                    'type' => 'hidden', 'name' => 'formHash', 'value' => '', '#required' => true,
                    '#validations' => array(
                        'callback' => array('mpForm_Validation', 'equals'),
                        'params'   => array($sessFormHash),
                        'errorMsg' => ''
                    )
                );
            }
            $this->setFormElement('formHash', $hashElement);
        }
    }


    protected function _takeoverRequestData()
    {
        foreach ($this->getRequest() as $name => $value) {
            $elements = $this->getElementsByName($name);
            if (count($elements) == 0) {
                continue;
            } elseif (count($elements) == 1) {

                $element = $elements[0];

                if ($element->getProperty('type') == 'select') {
                    $options = $element->getProperty('options');
                    foreach ($options as $pos => $option) {
                        if ($value == $option['v']) {
                            $options[$pos]['s'] = true;
                            $element->setValue($value);
                        } else {
                            $options[$pos]['s'] = false;
                        }
                    }
                    $element->setProperty('options', $options);
                } else {
                    $element->setValue($value);
                }
            } elseif (count($elements) > 1) {
                // radios
                foreach ($elements as $pos => $element) {
                    if ($element->getProperty('type') == 'radio') {
                        if ($element->getValue() == $value) {
                            $element->setAttribute('checked', 'checked');
                        } else {
                            $element->unsetAttribute('checked');
                        }
                    }
                }
//                $element->setValue($value);
            }
        }

        foreach ($_FILES as $name => $uploadFile) {
            $elements = $this->getElementsByName($name);
            if (count($elements) == 0) {
                continue;
            } elseif (count($elements) == 1) {
                if ($elements[0]->getProperty('type') == 'file') {
                    if (isset($_FILES[$name])) {
                         $elements[0]->setValue($_FILES[$name]);
                    }
                }
            }
            // @todo: add multiple file upload using one name list filename[]
        }
    }


    public function getElementsByName($name)
    {
        $elements = array();
        foreach ($this->getFormElements() as $id => $element) {
            if ($element->getAttribute('name') == $name) {
                $elements[] = $element;
            }
        }
        return $elements;
    }


    protected function _getOptionElementByName($name)
    {
        $requestValue = $this->getRequestItem($name);
        foreach ($this->getFormElements() as $id => $element) {
            if ($element->getAttribute('name') == $name && $requestValue == $element->getValue()) {
                return $element;
            }
        }
        return null;
    }

    /**
     * Dumps the content of passed variable and returns the result.
     *
     * @param  mixed   $var        The variable
     * @param  string  $label      Additional text to describe the variable
     * @param  bool    $formatted  Flag to return formated information
     * return  string
     */
    protected function _dumpVar($var, $label='', $formatted=true){
        $dump = ($label !== '') ? $label . ":\n" : '';
        if (is_object($var) || is_array($var)) {
            $dump .= print_r($var, true);
        } elseif (is_bool($var)) {
            $dump .= ($var == true) ? '(bool) true' : '(bool) false';
        } elseif (is_null($var)) {
            $dump .= '(is_null)';
        } elseif (is_string($var) && empty($var)) {
            $dump .= '(is_empty)';
        } else {
            $dump .= $var;
        }
        if ($formatted) {
            return '<pre>' . $dump . '</pre>';
        } else {
            return $dump;
        }
    }

}
